package com.bestom.waterquality.logic;

import android.app.Activity;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.TextView;

import com.bestom.waterquality.R;
import com.bestom.waterquality.WaterQualityApplication;
import com.bestom.waterquality.entity.Constant;
import com.bestom.waterquality.entity.IoChangeBean;
import com.bestom.waterquality.entity.NodeBean;
import com.bestom.waterquality.services.MQTTService;
import com.bestom.waterquality.services.MQTTService2;
import com.bestom.waterquality.util.ToastUtil;

import cn.wch.ch934xlib.CH934XManager;
import cn.wch.ch934xlib.exception.UartLibException;
import cn.wch.ch934xlib.gpio.GPIO_DIR;
import cn.wch.ch934xlib.gpio.GPIO_VALUE;
import cn.wch.ch934xlib.utils.LogUtil;
import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

/**
 * 外设状态
 */
public class PeripheralStatus {

    private Context mContext;
    private Activity mActivity;

    private PeripheralStatus() {
    }

    private static PeripheralStatus _instance = null;
    private UsbDevice mUsbDevice;

    public static PeripheralStatus getInstance() {
        if (_instance == null)
            _instance = new PeripheralStatus();
        return _instance;
    }

    private TextView peripheralInput1;
    private TextView peripheralInput2;
    private TextView peripheralInput3;
    private TextView peripheralInput4;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            getGPIOValue(mUsbDevice);
            mHandler.postDelayed(this,3000);
        }
    };

    public void setDataAndListen(Activity activity, Context context, View view) {

        if (mContext == null) {
            mContext = context;
            mActivity = activity;
            peripheralInput1 = view.findViewById(R.id.peripheral_input_1);
            peripheralInput2 = view.findViewById(R.id.peripheral_input_2);
            peripheralInput3 = view.findViewById(R.id.peripheral_input_3);
            peripheralInput4 = view.findViewById(R.id.peripheral_input_4);

            mUsbDevice = SerialPortSet.getInstance().getDevice();
            if (mUsbDevice != null) {
                setGPIODir(mUsbDevice, 1, GPIO_DIR.IN, peripheralInput4);
                mHandler.postDelayed(mRunnable,3000);
            }
        }
    }

    private void setGPIODir(UsbDevice device, int gpioNumber, GPIO_DIR dir, TextView mTextView) {
        LogUtil.d("setGPIODir:  " + dir + "   " + gpioNumber);
        Observable.create((ObservableOnSubscribe<String>) emitter -> {
            try {
                boolean ret = CH934XManager.getInstance().setGPIODir(device, gpioNumber, dir);
                if (!ret) {
                    emitter.onError(new Throwable("operation failed!"));
                } else {
                    emitter.onComplete();
                    return;
                }
            } catch (UartLibException e) {
                emitter.onError(new Throwable(e.getMessage()));
            }

        })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
                    }

                    @Override
                    public void onNext(@io.reactivex.annotations.NonNull String s) {

                    }

                    @Override
                    public void onError(@io.reactivex.annotations.NonNull Throwable e) {
                        mActivity.runOnUiThread(() -> mTextView.setText(e.getMessage()));
                    }

                    @Override
                    public void onComplete() {
                        switch (gpioNumber) {
                            case 1:
                                setGPIODir(mUsbDevice, 5, GPIO_DIR.IN, peripheralInput1);
                                break;
                            case 5:
                                setGPIODir(mUsbDevice, 8, GPIO_DIR.IN, peripheralInput2);
                                break;
                            case 8:
                                setGPIODir(mUsbDevice, 11, GPIO_DIR.IN, peripheralInput3);
                                break;
                            case 11:
                                getGPIOValue(mUsbDevice);
                                break;
                        }
                    }
                });
    }

    private void getGPIOValue(UsbDevice device) {
        Observable.create((ObservableOnSubscribe<String>) emitter -> {

            try {
                boolean ret = CH934XManager.getInstance().getGPIOValue(device);
                if (!ret) {
                    emitter.onError(new Throwable("get GPIO value fail!"));
                    return;
                }
                StringBuilder ioId = new StringBuilder();
                StringBuilder status = new StringBuilder();

                GPIO_VALUE gpio_value1 = CH934XManager.getInstance().queryGPIOValueFromCache(device, 1);
                if (!peripheralInput4.getText().equals(gpio_value1 == GPIO_VALUE.HIGH ? "高" : "低")) {
                    ioId.append("1,");
                    status.append(gpio_value1 == GPIO_VALUE.HIGH ? "1," : "0,");
                }
                mActivity.runOnUiThread(() -> {
                    peripheralInput4.setText(gpio_value1 == GPIO_VALUE.HIGH ? "高" : "低");
                });

                GPIO_VALUE gpio_value5 = CH934XManager.getInstance().queryGPIOValueFromCache(device, 5);
                if (!peripheralInput1.getText().equals(gpio_value5 == GPIO_VALUE.HIGH ? "高" : "低")) {
                    ioId.append("2,");
                    status.append(gpio_value5 == GPIO_VALUE.HIGH ? "1," : "0,");
                }
                mActivity.runOnUiThread(() -> peripheralInput1.setText(gpio_value5 == GPIO_VALUE.HIGH ? "高" : "低"));

                GPIO_VALUE gpio_value8 = CH934XManager.getInstance().queryGPIOValueFromCache(device, 8);
                if (!peripheralInput2.getText().equals(gpio_value8 == GPIO_VALUE.HIGH ? "高" : "低")) {
                    ioId.append("3,");
                    status.append(gpio_value8 == GPIO_VALUE.HIGH ? "1," : "0,");
                }
                mActivity.runOnUiThread(() -> peripheralInput2.setText(gpio_value8 == GPIO_VALUE.HIGH ? "高" : "低"));

                GPIO_VALUE gpio_value11 = CH934XManager.getInstance().queryGPIOValueFromCache(device, 11);
                if (!peripheralInput3.getText().equals(gpio_value11 == GPIO_VALUE.HIGH ? "高" : "低")) {
                    ioId.append("4,");
                    status.append(gpio_value11 == GPIO_VALUE.HIGH ? "1," : "0,");
                }
                mActivity.runOnUiThread(() -> peripheralInput3.setText(gpio_value11 == GPIO_VALUE.HIGH ? "高" : "低"));

                if (ioId.length() != 0){
                    if (WaterQualityApplication.mtIsOk){
                        MQTTService.publish(Constant.IoStateChangesPublishTopic, ioId.substring(0,ioId.length()-1),status.substring(0,ioId.length()-1));
                    }
                    if (WaterQualityApplication.mt2IsOk){
                        MQTTService2.publish(Constant.IoStateChangesPublishTopic,ioId.substring(0,ioId.length()-1),status.substring(0,ioId.length()-1));
                    }
                }

            } catch (UartLibException e) {
                emitter.onError(new Throwable(e.getMessage()));
            }

        })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
                    }

                    @Override
                    public void onNext(@io.reactivex.annotations.NonNull String s) {
                    }

                    @Override
                    public void onError(@io.reactivex.annotations.NonNull Throwable e) {

                        ToastUtil.toast(e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }
}
